home *** CD-ROM | disk | FTP | other *** search
- #include "main.h"
- #include "cursors.h"
- #include "draw.h"
-
- extern int isBackground;
- extern long timer();
-
- /*****************************************************************
- * *
- * This updates the ants pattern by shifting it to be in line with the current ticks. It checks to *
- * see how far it would be moving them, and if it is more then three pixels, it moves it only 3. *
- * Otherwise the crawling can look either jumpy or backwards. 2 would be preferable, but *
- * during large color-screen selects it often slows down to 3 ticks. *
- * *
- *****************************************************************/
-
- Pattern *getAnts( which )
- int which;
- {
- static int ants[ 2 ][ 7 ] = {{ 0x3e7c, 0xf8f1, 0xe3c7, 0x8f1f, 0x3e7c, 0xf8f1, 0xe3c7 },
- { 0x1f3e, 0x7cf8, 0xf1e3, 0xc78f, 0x1f3e, 0x7cf8, 0xf1e3 }};
-
- return(( Pattern* )&( ants[ which & 1 ][ 3 - which / 2 ] ));
- }
-
- int updateAnts( theData )
- dataPtr theData;
- {
- long tick;
- int change;
-
- tick = TickCount();
- change = tick - theData->antTick;
- theData->antTick = tick;
- if( change > maxAntDelta ) change = maxAntDelta;
- theData->antSkew = ( theData->antSkew + change ) & 7;
- return( change );
- }
-
- drawAnts( theData, change )
- dataPtr theData;
- int change;
- {
- PenState savePen;
- GrafPtr savePort;
- RgnHandle saveClip;
- Pattern *oldPat, *newPat, tempPat;
- int i;
-
- GetPort( &savePort );
- SetPort( theData->parent );
- GetPenState( &savePen );
- oldPat = getAnts(( theData->antSkew - change ) & 7 );
- newPat = getAnts( theData->antSkew );
- for( i = 0; i < 8; ++i ) tempPat[ i ] = ( *oldPat )[ i ] ^ ( *newPat )[ i ];
- PenPat( &tempPat );
- PenMode( patXor );
- PenSize( 1, 1 );
- saveClip = NewRgn();
- doMenuClip( saveClip );
- FrameRgn( theData->selRgn );
- SetClip( saveClip );
- DisposeRgn( saveClip );
- SetPenState( &savePen );
- SetPort( savePort );
- theData->changed = timer();
- theData->allBitsState |= bitsBadAnts;
- }
-
- /*****************************************************************
- * *
- * *
- *****************************************************************/
-
- dropSel( theData )
- dataPtr theData;
- {
- Rect *bounds;
-
- if( theData->isSelect )
- {
- if( theData->selActive ) --isBackground;
- theData->isSelect = 0;
- theData->selActive = 0;
- bounds = &( theData->selBits.bounds );
- CopyBig( &( theData->selBits ), &( theData->offBits ), bounds, bounds, srcCopy, theData->selRgn );
- DisposPtr( theData->selBits.baseAddr );
- SetEmptyRgn( theData->selRgn );
- theData->allBitsState |= bitsBadData;
- bounds = &( theData->dataRect );
- CopyBig( &( theData->offBits ), &( thePort->portBits ), bounds, bounds, srcCopy, NULL );
- }
- }
-
- /*****************************************************************
- * *
- * grabSel has one ugliness in it - rather than using eraseRect or somesuch, once it has copied *
- * the selection bits it copies them back with srcXor to erase them. This avoids all the business *
- * with setting up a grafPort. *
- * *
- *****************************************************************/
-
- grabSel( theData, bounds )
- dataPtr theData;
- Rect *bounds;
- {
- BitMap saveBits;
- RgnHandle saveVis;
- int bytes, errno;
-
- ++isBackground;
- theData->isSelect = -1;
- theData->selActive = -1;
- theData->selBits.bounds = *bounds;
- theData->selBits.rowBytes = bytes = (( bounds->right - bounds->left + 15 ) >> 3 ) & -2;
- theData->selBits.baseAddr = NewPtr(( long )bytes * ( bounds->bottom - bounds->top ));
- if( errno = MemError() ) hardPanic( errno, memPanic );
- RectRgn( theData->selRgn, bounds );
- CopyBig( &( theData->offBits ), &( theData->selBits ), bounds, bounds, srcCopy, NULL );
- CopyBig( &( theData->selBits ), &( theData->offBits ), bounds, bounds, srcXor, NULL );
- }
-
- /*****************************************************************
- * *
- * These routines collect the sum total of the edge regions of two rectangle frames of width 1. *
- * This will generally be 3 or less rectangles each way of width 1. These are then copied from *
- * source to dest. The copyEdges routine replaces a copyBits of the unionRect of the two, and *
- * cuts the total time between updates dramatically - from over 7 ticks in full-screen color to *
- * approximately 3 ticks. *
- * *
- *****************************************************************/
-
- collectRect( collection, theRect, count, which )
- int *collection, *theRect, *count, which;
- {
- int i = 0, bound, j = 0;
-
- bound = *count * 4;
- while( i < bound && collection[ i + which ] != theRect[ which ] ) i += 4;
- if( i == bound )
- {
- ++*count;
- while( j < 4 ) collection[ i++ ] = theRect[ j++ ];
- }
- else {
- which = 1 - which;
- j = which + i;
- collection[ j ] = min( collection[ j ], theRect[ which ] );
- collection[ j + 2 ] = max( collection[ j + 2 ], theRect[ which + 2 ] );
- }
- }
-
- collectSides( theRect, collection, count, which )
- int *theRect, *collection, *count, which;
- {
- int temp[ 4 ], i;
-
- for( i = 0; i < 4; ++i ) temp[ i ] = theRect[ i ];
- temp[ which + 2 ] = temp[ which ] + 1;
- collectRect( collection, temp, count, which );
- temp[ which ] = ( temp[ which + 2 ] = theRect[ which + 2 ] ) - 1;
- collectRect( collection, temp, count, which );
- }
-
- copyEdges( source, dest, oldRect, newRect, mode, mask )
- BitMap *source, *dest;
- Rect *oldRect, *newRect;
- int mode;
- RgnHandle mask;
- {
- Rect edgeRects[8], temp;
- int hcount = 0, vcount = 0, i;
-
- collectSides( oldRect, edgeRects, &hcount, horzEdges );
- if( newRect ) collectSides( newRect, edgeRects, &hcount, horzEdges );
- collectSides( oldRect, &( edgeRects[ hcount ] ), &vcount, vertEdges );
- if( newRect ) collectSides( newRect, &( edgeRects[ hcount ] ), &vcount, vertEdges );
- for( i = hcount; i < vcount + hcount; ++i )
- {
- ++edgeRects[ i ].top;
- --edgeRects[ i ].bottom;
- }
- hcount += vcount;
- for( i = 0; i < hcount; ++i )
- CopyBig( source, dest, &( edgeRects[ i ] ), &( edgeRects[ i ] ), mode, mask );
- }
-
- /*****************************************************************
- * *
- * This handles the dragging for selection of a rectangle with the marqee. It calls doBackground *
- * occasionally, and uses the updateAnts and copyEdges routines of above. dropSel is called at *
- * the beginning if there is a current selection, and grabSel is called at the end with the final *
- * selection information. *
- * *
- *****************************************************************/
-
- doSelect( theWindow, theEvent )
- WindowPeek theWindow;
- EventRecord *theEvent;
- {
- BitMap mainBits;
- PenState savePen;
- Rect newRect, oldRect;
- Point old, new, start;
- dataHandle theDataHand;
- dataPtr theData;
- long oldTicks = TickCount();
- int cont, shift, dh, dv, antSkew, newSkew, oldState;
-
- theDataHand = ( dataHandle )GetWRefCon( theWindow );
- HLock( theDataHand );
- theData = *theDataHand;
- oldState = stopData( theData, forceStop );
- dropSel( theData );
- mainBits = thePort->portBits;
-
- start = theEvent->where;
- GlobalToLocal( &start );
- GetPenState( &savePen );
- PenMode( patCopy );
- old.h = old.v = -32768;
- SetRect( &oldRect, start.h, start.v, start.h, start.v );
- do {
- cont = StillDown();
- GetMouse( &new );
- if( getModifiers() & shiftKey ) {
- dh = delta( new.h, start.h );
- dv = delta( new.v, start.v );
- if( dv < dh ) dh = dv;
- new.v = new.v > start.v ? start.v + dh : start.v - dh;
- new.h = new.h > start.h ? start.h + dh : start.h - dh;
- }
- if( new.v != old.v || new.h != old.h ) {
- newRect.top = min( new.v, start.v );
- newRect.left = min( new.h, start.h );
- newRect.bottom = max( new.v, start.v ) + 1;
- newRect.right = max( new.h, start.h ) + 1;
- SectRect( &newRect, &theData->dataRect, &newRect );
- if( !EqualRect( &newRect, &oldRect )) {
- copyEdges( &( theData->offBits ), &( theData->allBits ), &oldRect, NULL, srcCopy, NULL );
- if( updateAnts( theData ))
- PenPat( getAnts( theData->antSkew ));
- SetPortBits( &( theData->allBits ));
- FrameRect( &newRect );
- SetPortBits( &mainBits );
- copyEdges( &( theData->allBits ), &mainBits, &oldRect, &newRect, srcCopy, NULL );
- old = new;
- oldRect = newRect;
- }
- }
- if( updateAnts( theData )) {
- PenPat( getAnts( theData->antSkew ));
- FrameRect( &newRect );
- }
- doBackground( lotsElseToDo, noGray, NULL );
- } while( cont );
- theData->allBitsState |= bitsBadData + bitsBadSel;
- SetPenState( &savePen );
- if( new.v != start.v || new.h != start.h )
- grabSel( theData, &newRect );
- else copyEdges( &( theData->offBits ), &mainBits, &oldRect, NULL, srcCopy, NULL );
- restartData( theData, oldState );
- theData->allBitsState |= bitsBadSel + bitsBadData;
- theData->changed = timer();
- HUnlock( theDataHand );
- }
-
- /*****************************************************************
- * *
- * *
- *****************************************************************/
-
- doSelDrag( theWindow, theEvent )
- WindowPeek theWindow;
- EventRecord *theEvent;
- {
- BitMap mainBits;
- PenState savePen;
- Rect boundsRect, oldRect, newRect;
- Point old, new, start;
- dataHandle theDataHand;
- dataPtr theData;
- int dh, dv, active, cont, dir = noDir;
-
- theDataHand = ( dataHandle )GetWRefCon( theWindow );
- HLock( theDataHand );
- theData = *theDataHand;
- active = theData->selActive;
- oldRect = newRect = theData->selBits.bounds;
- if( theEvent->modifiers & optionKey )
- CopyBig( &( theData->selBits ), &( theData->offBits ), &oldRect, &oldRect, srcCopy, theData->selRgn );
- theData->selActive = 0;
- GetPenState( &savePen );
- old = theEvent->where;
- GlobalToLocal( &old );
- botRight( boundsRect ) = topLeft( boundsRect ) = start = old;
- SubPt( topLeft( oldRect ), &( topLeft( boundsRect )));
- AddPt( topLeft( theData->dataRect ), &( topLeft( boundsRect )));
- SubPt( botRight( oldRect ), &( botRight( boundsRect )));
- AddPt( botRight( theData->dataRect ), &( botRight( boundsRect )));
- boundsRect.right++;
- boundsRect.bottom++;
- mainBits = thePort->portBits;
- PenMode( patCopy );
- if( theEvent->modifiers & shiftKey ) dir = setMouseDir( old );
- do {
- cont = StillDown();
- GetMouse( &new );
- if( dir == horzDir ) new.v = old.v;
- else if( dir == vertDir ) new.h = old.h;
- myPinRect( &boundsRect, &new );
- dh = new.h - old.h;
- dv = new.v - old.v;
- if( dh || dv )
- {
- OffsetRect( &newRect, dh, dv );
- OffsetRgn( theData->selRgn, dh, dv );
- UnionRect( &oldRect, &newRect, &oldRect );
- CopyBig( &( theData->offBits ), &( theData->allBits ), &oldRect, &oldRect, srcCopy, NULL );
- CopyBig( &( theData->selBits ), &( theData->allBits ), &( theData->selBits.bounds ), &newRect, srcCopy, theData->selRgn );
- PenPat( getAnts( theData->antSkew ));
- SetPortBits( &( theData->allBits ));
- FrameRgn( theData->selRgn );
- SetPortBits( &mainBits );
- CopyBig( &( theData->allBits ), &( thePort->portBits ), &oldRect, &oldRect, srcCopy, NULL );
- old = new;
- oldRect = newRect;
- }
- HUnlock( theDataHand );
- doBackground( lotsElseToDo, noGray, NULL );
- HLock( theDataHand );
- theData = *theDataHand;
- }
- while( cont );
- theData->selBits.bounds = newRect;
- SetPenState( &savePen );
- theData->selActive = active;
- HUnlock( theDataHand );
- }
-
- /*****************************************************************
- * *
- * doBoxBrush does pencil or erasor drawing by setting the pensize and pattern. It is the only *
- * one of these routines that draws directly onto the screen rather than drawing off-screen and *
- * copying, as it never erases old changes, but merely adds more. *
- * *
- *****************************************************************/
-
- doBoxBrush( theWindow, theEvent, size, pattern )
- WindowPeek theWindow;
- EventRecord *theEvent;
- int size;
- {
- BitMap mainBits;
- PenState saveState;
- Point old, new;
- RgnHandle newClip;
- dataHandle theDataHand;
- dataPtr theData;
- int cont, oldState, dir = noDir, off;
-
- theDataHand = ( dataHandle )GetWRefCon( theWindow );
- HLock( theDataHand );
- theData = *theDataHand;
- oldState = stopData( theData, forceStop );
- BlockMove( theData->bases[0], theData->bases[1], theData->planeSize );
- mainBits = theWindow->port.portBits;
- old = theEvent->where;
- GlobalToLocal( &old );
-
- newClip = NewRgn();
- RectRgn( newClip, &( theData->dataRect ));
- if( theData->isSelect )
- DiffRgn( newClip, theData->selRgn, newClip );
-
- GetPenState( &saveState );
- PenMode( patCopy );
- PenSize( size, size );
- off = size / 2;
- SetPortBits( &( theData->offBits ));
- PenPat( pattern || GetPixel( old.h, old.v ) ? &white : &black );
- MoveTo( old.h - off, old.v - off );
- Line( 0,0 );
- SetPortBits( &mainBits );
- Line( 0,0 );
- if( theEvent->modifiers & shiftKey ) dir = setMouseDir( old );
- do {
- cont = StillDown();
- GetMouse( &new );
- if( dir == horzDir ) new.v = old.v;
- else if( dir == vertDir ) new.h = old.h;
- if( old.h != new.h || old.v != new.v )
- {
- SetClip( newClip );
- LineTo( new.h - off, new.v - off );
- MoveTo( old.h - off, old.v - off );
- SetPortBits( &( theData->offBits ));
- ClipRect( &( theData->dataRect ));
- LineTo( new.h - off, new.v - off );
- SetPortBits( &mainBits );
- old = new;
- }
- doBackground( someElseToDo, noGray, NULL );
- }
- while( cont );
-
- ClipRect( &( theWindow->port.portRect ));
- DisposeRgn( newClip );
- SetPenState( &saveState );
- madeChange( theData );
- restartData( theData, oldState );
- HUnlock( theDataHand );
- }
-
- setMouseDir( old )
- Point old;
- {
- Point new;
- int dir = 0, dh, dv;
-
- while( !dir && StillDown() )
- {
- GetMouse( &new );
- dh = delta( new.h, old.h );
- dv = delta( new.v, old.v );
- if( dv >= 2 || dh >= 2 ) dir = dh >= dv ? horzDir : vertDir;
- }
- return( dir );
- }
-
- doBoxedShape( theWindow, theEvent, whichShape )
- WindowPeek theWindow;
- EventRecord *theEvent;
- int whichShape;
- {
- BitMap mainBits, buffBits;
- PenState savePen;
- Rect theRect, newRect;
- Point old, new, start;
- RgnHandle maskRgn;
- dataHandle theDataHand;
- dataPtr theData;
- int oldState, angle, dh, dv, cont;
-
- theDataHand = ( dataHandle )GetWRefCon( theWindow );
- HLock( theDataHand );
- theData = *theDataHand;
- oldState = stopData( theData, forceStop );
- BlockMove( theData->bases[0], theData->bases[1], theData->planeSize );
- mainBits = theWindow->port.portBits;
- buffBits = theData->offBits;
- buffBits.baseAddr = theData->bases[1];
-
- if( theData->isSelect ) {
- maskRgn = NewRgn();
- RectRgn( maskRgn, &( theData->dataRect ));
- DiffRgn( maskRgn, theData->selRgn, maskRgn );
- } else maskRgn = NULL;
-
- start = theEvent->where;
- GlobalToLocal( &start );
- GetPenState( &savePen );
- PenMode( patCopy );
- PenPat( GetPixel( start.h, start.v ) ? &white : &black );
- old.h = old.v = -32768;
- theRect.left = theRect.right = start.h;
- theRect.top = theRect.bottom = start.v;
- do {
- cont = StillDown();
- GetMouse( &new );
- if( getModifiers() & shiftKey )
- {
- dh = delta( new.h, start.h );
- dv = delta( new.v, start.v );
- if( whichShape != lineCurs )
- dv = dh = min( dh, dv );
- else if( dh && dv )
- {
- angle = AngleFromSlope( FixRatio( -dv, dh ));
- if( angle < 23 ) dv = 0;
- else if( angle > 67 ) dh = 0;
- else dh = dv = min( dh, dv );
- }
- new.v = new.v > start.v ? start.v + dv : start.v - dv;
- new.h = new.h > start.h ? start.h + dh : start.h - dh;
- }
- if( new.v != old.v || new.h != old.h )
- {
- CopyBig( &buffBits, &( theData->offBits ), &theRect, &theRect, srcCopy, NULL );
- newRect.top = min( new.v, start.v );
- newRect.left = min( new.h, start.h );
- newRect.bottom = max( new.v, start.v ) + 1;
- newRect.right = max( new.h, start.h ) + 1;
- SetPortBits( &( theData->offBits ));
-
- if( whichShape == rectCurs )
- PaintRect( &newRect );
- else if( whichShape == elipseCurs )
- PaintOval( &newRect );
- else {
- MoveTo( start.h, start.v );
- LineTo( new.h, new.v );
- }
-
- SetPortBits( &mainBits );
- UnionRect( &newRect, &theRect, &theRect );
- SectRect( &( theData->dataRect ), &theRect, &theRect );
- CopyBig( &( theData->offBits ), &mainBits, &theRect, &theRect, srcCopy, maskRgn );
- theRect = newRect;
- old = new;
- }
- doBackground( lotsElseToDo, noGray, NULL );
- }
- while( cont );
- madeChange( theData );
- if( maskRgn ) DisposeRgn( maskRgn );
- restartData( theData, oldState );
- SetPenState( &savePen );
- HUnlock( theDataHand );
- }
-
- /*****************************************************************
- * *
- * These routines operate directly on the bitmap they are handed. *
- * *
- *****************************************************************/
-
- randomize( sbits, dest )
- BitMap *sbits;
- register int *dest;
- {
- register int shift = 16;
- register long size, localseed, mult = randomMult, add = randomAdd;
-
- size = ( long )sbits->rowBytes * ( sbits->bounds.bottom - sbits->bounds.top ) / 2;
- localseed = TickCount();
- while( size )
- {
- localseed *= mult;
- localseed += add;
- *dest = ( unsigned int )( localseed >> shift );
- ++dest;
- --size;
- }
- }
-
- eraseData( sbits, dest )
- BitMap *sbits;
- register long *dest;
- {
- register long size;
-
- size = ( long )sbits->rowBytes * ( sbits->bounds.bottom - sbits->bounds.top ) / 4;
- while( size )
- {
- *dest = 0;
- ++dest;
- --size;
- }
- while( size-- ) *dest++ = 0;
- }
-
- fillData( sbits, dest )
- BitMap *sbits;
- register long *dest;
- {
- register long size, filler = -1;
-
- size = ( long )sbits->rowBytes * ( sbits->bounds.bottom - sbits->bounds.top ) / 4;
- while( size )
- {
- *dest = filler;
- ++dest;
- --size;
- }
- while( size-- ) *dest++ = 0;
- }
-
- invertData( sbits, dest )
- BitMap *sbits;
- register long *dest;
- {
- register long size, *source;
-
- size = ( long )sbits->rowBytes * ( sbits->bounds.bottom - sbits->bounds.top ) / 4;
- source = ( long * )sbits->baseAddr;
- while( size )
- {
- *dest = ~*source;
- ++dest; /* this produces more efficient code then *…++, but in neither */
- ++source; /* case does it actually use the postdecrement mode. */
- --size;
- }
- }